D:\a\tools.proto\tools.proto\compiler\src\gen\base\union.rs
Line | Count | Source |
1 | | // Copyright (c) 2024, BlockProject 3D |
2 | | // |
3 | | // All rights reserved. |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without modification, |
6 | | // are permitted provided that the following conditions are met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright notice, |
9 | | // this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above copyright notice, |
11 | | // this list of conditions and the following disclaimer in the documentation |
12 | | // and/or other materials provided with the distribution. |
13 | | // * Neither the name of BlockProject 3D nor the names of its contributors |
14 | | // may be used to endorse or promote products derived from this software |
15 | | // without specific prior written permission. |
16 | | // |
17 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
21 | | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 | | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
23 | | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
24 | | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
25 | | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
26 | | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | |
29 | | use crate::compiler::message::Referenced; |
30 | | use crate::compiler::union::{DiscriminantField, Union}; |
31 | | use crate::compiler::util::types::{PtrKey, TypeMapper}; |
32 | | use crate::gen::base::map::TypePathMapper; |
33 | | use crate::gen::template::hook::TemplateHooks; |
34 | | use crate::gen::template::Template; |
35 | | use itertools::Itertools; |
36 | | use std::collections::HashSet; |
37 | | |
38 | | pub trait Utilities: crate::gen::base::structure::Utilities { |
39 | | fn gen_discriminant_path(discriminant: &DiscriminantField) -> String; |
40 | | fn gen_discriminant_path_mut(discriminant: &DiscriminantField) -> String; |
41 | | } |
42 | | |
43 | 6 | fn gen_union_from_slice_impl<T: TypeMapper>( |
44 | 6 | u: &Union, |
45 | 6 | template: &Template, |
46 | 6 | type_path_map: &TypePathMapper<T>, |
47 | 6 | function: &str, |
48 | 6 | ) -> String { |
49 | 6 | let cases = u |
50 | 6 | .cases |
51 | 6 | .iter() |
52 | 32 | .map(|case| { |
53 | 32 | let mut scope = template.scope(); |
54 | 32 | scope.var("name", &case.name).var_d("case", case.case); |
55 | 32 | match &case.item_type { |
56 | 6 | None => scope.render(function, &["none.case"]).unwrap(), |
57 | 26 | Some(item_type) => { |
58 | 26 | scope.var("type_name", type_path_map.get(item_type)).render(function, &["content.case"]).unwrap() |
59 | | } |
60 | | } |
61 | 32 | }) |
62 | 6 | .join(""); |
63 | 6 | let mut scope = template.scope(); |
64 | 6 | scope.var("cases", cases); |
65 | 6 | if u.has_content() { Branch (65:8): [True: 4, False: 2]
Branch (65:8): [True: 0, False: 0]
Branch (65:8): [Folded - Ignored]
|
66 | 4 | scope.render_to_var(function, &["content"], "fragment").unwrap(); |
67 | 4 | } else { |
68 | 2 | scope.render_to_var(function, &["none"], "fragment").unwrap(); |
69 | 2 | } |
70 | 6 | scope.render("", &[function]).unwrap() |
71 | 6 | } |
72 | | |
73 | 7 | fn gen_union_write_to_impl<T: TypeMapper>( |
74 | 7 | u: &Union, |
75 | 7 | template: &Template, |
76 | 7 | type_path_map: &TypePathMapper<T>, |
77 | 7 | function: &str, |
78 | 7 | ) -> String { |
79 | 7 | let mut scope = template.scope(); |
80 | 7 | if u.has_content() { Branch (80:8): [True: 5, False: 2]
Branch (80:8): [True: 0, False: 0]
Branch (80:8): [Folded - Ignored]
|
81 | 5 | let cases = u |
82 | 5 | .cases |
83 | 5 | .iter() |
84 | 40 | .filter_map(|case| { |
85 | 40 | let mut scope = template.scope(); |
86 | 40 | scope.var("name", &case.name).var_d("case", case.case); |
87 | 40 | case.item_type.as_ref().map(|item_type| { |
88 | 37 | scope.var("type_name", type_path_map.get(item_type)).render(function, &["content.case"]).unwrap() |
89 | 40 | }) |
90 | 40 | }) |
91 | 5 | .join(""); |
92 | 5 | scope.var("cases", cases).render_to_var(function, &["content"], "fragment").unwrap(); |
93 | 5 | } else { |
94 | 2 | scope.render_to_var(function, &["none"], "fragment").unwrap(); |
95 | 2 | } |
96 | 7 | scope.render("", &[function]).unwrap() |
97 | 7 | } |
98 | | |
99 | 6 | fn gen_union_set_discriminant(u: &Union, template: &Template) -> String { |
100 | 6 | let cases = u |
101 | 6 | .cases |
102 | 6 | .iter() |
103 | 32 | .map(|case| { |
104 | 32 | let mut scope = template.scope(); |
105 | 32 | scope.var("name", &case.name).var_d("case", case.case); |
106 | 32 | match &case.item_type { |
107 | 26 | Some(_) => scope.render("setter", &["ref"]).unwrap(), |
108 | 6 | None => scope.render("setter", &["none"]).unwrap(), |
109 | | } |
110 | 32 | }) |
111 | 6 | .join(""); |
112 | 6 | template.scope().var("cases", cases).render("", &["setter"]).unwrap() |
113 | 6 | } |
114 | | |
115 | 6 | fn gen_union_as_getters<T: TypeMapper>(u: &Union, template: &Template, type_path_map: &TypePathMapper<T>) -> String { |
116 | 6 | let cases = u |
117 | 6 | .cases |
118 | 6 | .iter() |
119 | 32 | .map(|case| { |
120 | 32 | let mut scope = template.scope(); |
121 | 32 | scope.var("name", &case.name); |
122 | 26 | match &case.item_type { |
123 | 22 | Some(Referenced::Struct(v)) => { |
124 | 22 | scope.var("type_name", type_path_map.get(v)).render("getters", &["struct"]).unwrap() |
125 | | } |
126 | 4 | Some(Referenced::Message(v)) => { |
127 | 4 | scope.var("type_name", type_path_map.get(v)).render("getters", &["message"]).unwrap() |
128 | | } |
129 | 6 | None => scope.render("getters", &["none"]).unwrap(), |
130 | | } |
131 | 32 | }) |
132 | 6 | .join(""); |
133 | 6 | template.scope().var("cases", cases).render("", &["getters"]).unwrap() |
134 | 6 | } |
135 | | |
136 | 6 | fn gen_decl<T: TypeMapper>( |
137 | 6 | u: &Union, |
138 | 6 | template: &Template, |
139 | 6 | type_path_map: &TypePathMapper<T>, |
140 | 6 | function: &str, |
141 | 6 | ) -> String { |
142 | 6 | let cases = u |
143 | 6 | .cases |
144 | 6 | .iter() |
145 | 26 | .map(|case| match &case.item_type { |
146 | 6 | None => template.scope().var("name", &case.name).render(function, &["none"]).unwrap(), |
147 | 22 | Some(Referenced::Struct(v)) => template |
148 | 22 | .scope() |
149 | 22 | .var("name", &case.name) |
150 | 22 | .var("type_name", type_path_map.get(v)) |
151 | 22 | .render(function, &["struct"]) |
152 | 22 | .unwrap(), |
153 | 4 | Some(Referenced::Message(v)) => template |
154 | 4 | .scope() |
155 | 4 | .var("name", &case.name) |
156 | 4 | .var("type_name", type_path_map.get(v)) |
157 | 4 | .render(function, &["message"]) |
158 | 4 | .unwrap(), |
159 | 32 | }) |
160 | 6 | .join(""); |
161 | 6 | template.scope().var("cases", cases).render("", &[function]).unwrap() |
162 | 6 | } |
163 | | |
164 | 6 | fn gen_decl_unique<T: TypeMapper>( |
165 | 6 | u: &Union, |
166 | 6 | template: &Template, |
167 | 6 | type_path_map: &TypePathMapper<T>, |
168 | 6 | function: &str, |
169 | 6 | ) -> String { |
170 | 6 | let mut found = HashSet::new(); |
171 | 6 | let cases = u |
172 | 6 | .cases |
173 | 6 | .iter() |
174 | 26 | .filter_map(|case| match &case.item_type { |
175 | 6 | None => Some(template.scope().var("name", &case.name).render(function, &["none"]).unwrap()), |
176 | 22 | Some(Referenced::Struct(v)) => { |
177 | 22 | if !found.contains(&v.ptr_key()) { Branch (177:20): [True: 22, False: 0]
Branch (177:20): [True: 0, False: 0]
Branch (177:20): [Folded - Ignored]
|
178 | 22 | found.insert(v.ptr_key()); |
179 | 22 | Some( |
180 | 22 | template |
181 | 22 | .scope() |
182 | 22 | .var("name", &case.name) |
183 | 22 | .var("type_name", type_path_map.get(v)) |
184 | 22 | .render(function, &["struct"]) |
185 | 22 | .unwrap(), |
186 | 22 | ) |
187 | | } else { |
188 | 0 | None |
189 | | } |
190 | | } |
191 | 4 | Some(Referenced::Message(v)) => { |
192 | 4 | if !found.contains(&v.ptr_key()) { Branch (192:20): [True: 4, False: 0]
Branch (192:20): [True: 0, False: 0]
Branch (192:20): [Folded - Ignored]
|
193 | 4 | found.insert(v.ptr_key()); |
194 | 4 | Some( |
195 | 4 | template |
196 | 4 | .scope() |
197 | 4 | .var("name", &case.name) |
198 | 4 | .var("type_name", type_path_map.get(v)) |
199 | 4 | .render(function, &["message"]) |
200 | 4 | .unwrap(), |
201 | 4 | ) |
202 | | } else { |
203 | 0 | None |
204 | | } |
205 | | } |
206 | 32 | }) |
207 | 6 | .join(""); |
208 | 6 | template.scope().var("cases", cases).render("", &[function]).unwrap() |
209 | 6 | } |
210 | | |
211 | 6 | pub fn generate<'variable, U: Utilities, T: TypeMapper>( |
212 | 6 | mut template: Template<'_, 'variable>, |
213 | 6 | u: &'variable Union, |
214 | 6 | type_path_map: &'variable TypePathMapper<T>, |
215 | 6 | hooks: &TemplateHooks, |
216 | 6 | ) -> String { |
217 | 6 | template |
218 | 6 | .var( |
219 | 6 | "discriminant_raw_type", |
220 | 6 | U::get_field_type(u.discriminant.get_leaf_fixed().bits_type), |
221 | 6 | ) |
222 | 6 | .var("union_name", &u.name) |
223 | 6 | .var("discriminant_path_mut", U::gen_discriminant_path_mut(&u.discriminant)) |
224 | 6 | .var("discriminant_path", U::gen_discriminant_path(&u.discriminant)) |
225 | 6 | .var("discriminant_type", type_path_map.get(&u.discriminant.root)); |
226 | 6 | let mut code = gen_decl(u, &template, type_path_map, "decl"); |
227 | 6 | for func0 in hooks.get_functions("decl") { |
228 | 0 | code += &gen_decl(u, &template, type_path_map, func); |
229 | 0 | } |
230 | 6 | for func in hooks.get_functions("decl_unique") { |
231 | 6 | code += &gen_decl_unique(u, &template, type_path_map, func); |
232 | 6 | } |
233 | 6 | code += &gen_union_from_slice_impl::<T>(u, &template, type_path_map, "from_bytes"); |
234 | 6 | for func0 in hooks.get_functions("from_bytes") { |
235 | 0 | code += &gen_union_from_slice_impl::<T>(u, &template, type_path_map, func); |
236 | 0 | } |
237 | 6 | code += &gen_union_write_to_impl::<T>(u, &template, type_path_map, "write_to"); |
238 | 6 | for func1 in hooks.get_functions("write_to") { |
239 | 1 | code += &gen_union_write_to_impl::<T>(u, &template, type_path_map, func); |
240 | 1 | } |
241 | 6 | code += &gen_union_set_discriminant(u, &template); |
242 | 6 | code += &gen_union_as_getters(u, &template, type_path_map); |
243 | 6 | code |
244 | 6 | } |